package com.kjlink.widget.monitoring.repository;

import com.kjlink.widget.monitoring.entity.MonitorEventBatch;
import com.kjlink.widget.monitoring.entity.MonitorRawEvent;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

/**
 * 描述:
 *
 * @author Vic.xu
 * @since 2025-08-05 10:51
 */
@Repository
public interface MonitorEventBatchRepository extends JpaRepository<MonitorEventBatch, String> {

    /**
     * 查询类型未上送的批次, 且持续时间包含当前事件的时间
     * 核心方法：判断是否存在可合并的批次
     *
     * @param eventType 事件类型
     * @param occurTime 事件发生时间 在批次的开始时间和结束时间之间
     * @param status    批次状态
     */
    @Query("SELECT b FROM MonitorEventBatch b " +
            "WHERE b.eventType = :eventType " +
            "AND b.firstOccurTime < :occurTime AND b.endTime >= :occurTime " +
            "AND b.status = :status")
    List<MonitorEventBatch> findFirstPendingBatchWithPageable(
            @Param("eventType") String eventType,
            @Param("occurTime") LocalDateTime occurTime,
            @Param("status") MonitorEventBatch.BatchStatus status,
            Pageable pageable);

    /**
     * 默认方法：封装Pageable参数（只取第一条），暴露给调用方
     * 调用方无需关心分页参数，直接使用此方法
     *
     * @param eventType 事件类型
     * @param occurTime 事件发生时间 在批次的开始时间和结束时间之间
     * @param status    批次状态
     */
    default Optional<MonitorEventBatch> findFirstPendingBatch(
            String eventType,
            LocalDateTime occurTime,
            MonitorEventBatch.BatchStatus status) {
        // 在默认方法中创建分页参数（只取第一条）
        Pageable firstPage = PageRequest.of(0, 1);
        // 调用带分页参数的底层方法
        // 调用底层方法获取List，再取第一个元素
        List<MonitorEventBatch> resultList = findFirstPendingBatchWithPageable(
                eventType, occurTime, status, firstPage);
        // 从List中提取第一条（为空则返回Optional.empty()）
        return resultList.stream().findFirst();
    }

    /**
     * 查询所有未上送的批次(endTime 小于当前时间)
     * 用于定时任务批量上送第三方
     */
    @Query("SELECT b FROM MonitorEventBatch b " +
            "WHERE b.status = :status " +
            "AND b.endTime <= CURRENT_TIMESTAMP " +
            "AND (:lastOpTime IS NULL OR b.endTime > :lastOpTime)")
    List<MonitorEventBatch> findPendingBatches(
            @Param("status") MonitorEventBatch.BatchStatus status,
            @Param("lastOpTime") LocalDateTime lastOpTime
    );

    /**
     * 根据批次号查询（精确匹配）
     */
    Optional<MonitorEventBatch> findByBatchNo(String batchNo);

    Page<MonitorRawEvent> findPageByBatchNo(String batchNo, Pageable pageable);

    /**
     * 更新批次状态为过期
     *
     * @param newStatus  新状态
     * @param oldStatus  旧状态
     * @param endTime    结束时间 的 end
     * @param lastOpTime 结束时间 的 start
     */
    @Transactional
    @Modifying
    @Query("UPDATE MonitorEventBatch b " +
            "SET b.status = :newStatus " +
            "WHERE b.status = :oldStatus " +
            "AND b.endTime <= :endTime " +
            "AND (:lastOpTime IS NULL OR b.endTime > :lastOpTime)")
    int updateExpiredBatches(
            @Param("newStatus") MonitorEventBatch.BatchStatus newStatus,
            @Param("oldStatus") MonitorEventBatch.BatchStatus oldStatus,
            @Param("endTime") LocalDateTime endTime,
            @Param("lastOpTime") LocalDateTime lastOpTime
    );

    /**
     * 根据状态查询批次
     *
     * @param status   批次状态
     * @param pageable 分页参数
     */
    Page<MonitorEventBatch> findByStatus(MonitorEventBatch.BatchStatus status, Pageable pageable);


}

